/*
 *  The MIT License
 * 
 *  Copyright 2011 Jeremy Heng | Jaybles | Vxtherael.
 * 
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 * 
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 * 
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 */

package com.codesinverse.neuralnetworks.perceptrons;

import com.codesinverse.neuralnetworks.perceptrons.exceptions.InputNodeNotFoundInLeadInException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

/**
 *
 * @author Jeremy Heng | Jaybles | Vxtherael
 */
public class ThresholdSwitchPerceptron extends PerceptronImpl implements Thresholdable {

    protected Map<Perceptron, Integer> leadIn = new HashMap<Perceptron, Integer>();
    protected int threshold = 1;

    public ThresholdSwitchPerceptron(PerceptronType type) {
        super(type);
    }

    public ThresholdSwitchPerceptron() {
        super(PerceptronType.Undefined);
    }

    @Override
    public int emit() {
        return passesThreshold() ? (this.emit = 1) : (this.emit = 0);
    }

    private boolean passesThreshold() {
        return (summation() >= this.threshold) ? true : false;
    }

    public int summation() {
        int summation = 0;
        for (Map.Entry<Perceptron, Integer> entry : this.leadIn.entrySet())
        {
            summation += entry.getKey().emit() * entry.getValue();
        }
        return summation;
    }

    public Map<Perceptron, Integer> geInputNodes() {
        return this.leadIn;
    }

    public void addInputNode(Perceptron node, Integer weight) {
        this.leadIn.put(node, weight);
    }

    public void removeInputNode(Perceptron node) {
        this.leadIn.remove(node);
    }

    public Map<Perceptron, Integer> getLeadIn() {
        return this.leadIn;
    }

    public void setLeadIn(Map<Perceptron, Integer> leadIn) {
        this.leadIn = leadIn;
    }

    public int getThreshold() {
        return threshold;
    }

    public void setThreshold(int threshold) {
        this.threshold = threshold;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        ThresholdSwitchPerceptron other = (ThresholdSwitchPerceptron) obj;
        if (!super.equals(other)) {
            return false;
        }
        if (this.leadIn != other.leadIn && (this.leadIn == null || !this.leadIn.equals(other.leadIn))) {
            return false;
        }
        if (this.threshold != other.threshold) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 53 * hash + (this.leadIn != null ? this.leadIn.hashCode() : 0);
        hash = 53 * hash + this.threshold;
        hash = 53 * hash + super.hashCode();
        return hash;
    }

    public void modifyInputNodeWeight(Perceptron node, Integer weight) throws InputNodeNotFoundInLeadInException {
        if (this.leadIn.containsKey(node)) {
            this.addInputNode(node, weight);
        }
        else {
            throw new InputNodeNotFoundInLeadInException();
        }
    }

    @Override
    public String toString() {
        String toString = super.toString() + "\n";
        toString += "[\nthreshold=" + this.threshold + "\n";
        for (Entry<Perceptron, Integer> entry : this.leadIn.entrySet()) {
            toString += "nodeID=" + entry.getKey().getID() + " -:- weight=" + entry.getValue() + "\n";
        }
        toString = toString.substring(0, toString.length() - 1);
        toString += "\n]";
        return toString;
    }


}
